/***************************************************************************
 *   Copyright (c) 2016 Stefan Tröger <stefantroeger@gmx.net>              *
 *                                                                         *
 *   This file is part of the FreeCAD CAx development system.              *
 *                                                                         *
 *   This library is free software; you can redistribute it and/or         *
 *   modify it under the terms of the GNU Library General Public           *
 *   License as published by the Free Software Foundation; either          *
 *   version 2 of the License, or (at your option) any later version.      *
 *                                                                         *
 *   This library  is distributed in the hope that it will be useful,      *
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
 *   GNU Library General Public License for more details.                  *
 *                                                                         *
 *   You should have received a copy of the GNU Library General Public     *
 *   License along with this library; see the file COPYING.LIB. If not,    *
 *   write to the Free Software Foundation, Inc., 59 Temple Place,         *
 *   Suite 330, Boston, MA  02111-1307, USA                                *
 *                                                                         *
 ***************************************************************************/


#include "pch.h"
#include <Base/Console.h>
#include <Base/Exception.h>

#include <Base/Writer.h>


#include "ExtensionContainer.h"


using namespace App;

TYPESYSTEM_SOURCE(App::ExtensionContainer, App::PropertyContainer)

ExtensionContainer::ExtensionContainer() {

}

ExtensionContainer::~ExtensionContainer(){}

void ExtensionContainer::registerExtension(Base::Type extension, Extension* ext){}

bool ExtensionContainer::hasExtension(Base::Type t, bool derived) const {

    //check for the exact type
    bool found = _extensions.find(t) != _extensions.end();
    if(!found && derived) {
        //and for types derived from it, as they can be cast to the extension
        for(auto entry : _extensions) {
            if(entry.first.isDerivedFrom(t))
                return true;
        }
        return false;
    }
    return found;
}

bool ExtensionContainer::hasExtension(const std::string& name) const{return 0;}


Extension* ExtensionContainer::getExtension(Base::Type t, bool derived, bool no_except) const {

    auto result = _extensions.find(t);
    if((result == _extensions.end()) && derived) {
        //we need to check for derived types
        for(auto entry : _extensions) {
            if(entry.first.isDerivedFrom(t))
                return entry.second;
        }
        if(no_except)
            return nullptr;
        //if we arrive here we don't have anything matching
        throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
    }
    else if (result != _extensions.end()) {
        return result->second;
    }
    else {
        if(no_except)
            return nullptr;
        //if we arrive here we don't have anything matching
        throw Base::TypeError("ExtensionContainer::getExtension: No extension of given type available");
    }
}

bool ExtensionContainer::hasExtensions() const {

    return !_extensions.empty();
}

Extension* ExtensionContainer::getExtension(const std::string& name) const{return nullptr;}

std::vector< Extension* > ExtensionContainer::getExtensionsDerivedFrom(Base::Type type) const {

    std::vector<Extension*> vec;
    //and for types derived from it, as they can be cast to the extension
    for(auto entry : _extensions) {
        if(entry.first.isDerivedFrom(type))
            vec.push_back(entry.second);
    }
    return vec;
}

void ExtensionContainer::getPropertyList(std::vector< Property* >& List) const{}

void ExtensionContainer::getPropertyMap(std::map< std::string, Property* >& Map) const{}

Property* ExtensionContainer::getPropertyByName(const char* name) const{return nullptr;}


short int ExtensionContainer::getPropertyType(const Property* prop) const{return 1;}

short int ExtensionContainer::getPropertyType(const char* name) const{return 1;}


const char* ExtensionContainer::getPropertyName(const Property* prop) const{return nullptr;}

const char* ExtensionContainer::getPropertyGroup(const Property* prop) const{return nullptr;}

const char* ExtensionContainer::getPropertyGroup(const char* name) const{return nullptr;}


const char* ExtensionContainer::getPropertyDocumentation(const Property* prop) const{return nullptr;}

const char* ExtensionContainer::getPropertyDocumentation(const char* name) const{return nullptr;}

void ExtensionContainer::onChanged(const Property* prop){return ;}

void ExtensionContainer::Save(Base::Writer& writer) const {

    //Note: save extensions must be called first to ensure that the extension element is always the
    //      very first inside the object element. This is needed since extension element works together with
    //      an object attribute, and if another element would be read first the object attributes would be
    //      cleared.
    saveExtensions(writer);
    App::PropertyContainer::Save(writer);
}

void ExtensionContainer::Restore(Base::XMLReader& reader) {

    //restore dynamic extensions.
    //Note 1: The extension element must be read first, before all other object elements. That is
    //        needed as the element works together with an object element attribute, which would be
    //        cleared if another attribute is read first
    //Note 2: This must happen before the py object of this container is used, as only in the
    //        pyobject constructor the extension methods are added to the container.
    restoreExtensions(reader);
    App::PropertyContainer::Restore(reader);
}

void ExtensionContainer::saveExtensions(Base::Writer& writer) const{return ;}

void ExtensionContainer::restoreExtensions(Base::XMLReader& reader){return ;}
